﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Security.AccessControl;

public partial class gbr
{
    //public const int iMaxColumnCount = 32;
    protected struct ResultRow
    {
        public Int64 PK;
        public StringBuilder [] sb;
        public string FileName;
        public int MaxColumnCount;
        public long FilePosition;
        public long FileNameHash;
        public ResultRow(Int64 iPk, string sFileName, int iMaxColumnCount)
        {
            PK = iPk;
            MaxColumnCount = iMaxColumnCount;
            sb = new StringBuilder[MaxColumnCount];
            for (int i = 0; i < MaxColumnCount; i++)
                sb[i] = new StringBuilder();
            FileName = sFileName;
            FilePosition = 0;
            FileNameHash = gbr.Hash_64(sFileName);
        }
        public void Reset()
        {
            FilePosition = -1;
            for (int i = 0; i < MaxColumnCount; i++)
                sb[i].Length = 0;
        }
        public void Reset(Int64 iPk)
        {
            PK = iPk;
            Reset();
        }
        public void Reset(Int64 iPk, string sFileName)
        {
            FileName = sFileName;
            FileNameHash = gbr.Hash_64(sFileName);
            Reset(iPk);
        }
    }
    protected class XRow
    {
        public ResultRow resultRow;
        protected int iColumnCount;
        protected int MaxColumnCount;
        #region Init
        public XRow(Int64 pk, string fileName, int iMaxColumnCount)
        {
            iColumnCount = 0;
            MaxColumnCount = iMaxColumnCount;
            resultRow = new ResultRow(pk, fileName, MaxColumnCount);
        }

        public virtual void Reset(long pk, string fileName)
        {
            resultRow.Reset(pk, fileName);
        }
        #endregion Init
        public enum XRowFindState { XmlRowFindRowStartTag, XmlRowFindColTag, XmlRowSkipColTag, XmlRowSaveColTag, XmlRowSkipRestOfEndTag, XmlRowFoundRow };
        #region Find data rows and data for the columns
        public virtual XRowFindState FindNext(ref byte[] ba, ref int iBuffer, int lenBuffer)
        { // Return true if new row filled, return false if
            return XRowFindState.XmlRowFindRowStartTag;
        }
        #endregion Find data rows and data for the columns
    }
    protected class XmlRow: XRow
    {
        public const int MAX_TAGNAME_LENGTH = 256;
        protected struct FindSpecificTag
        {
            public byte[] baTagToFind;
            public int iTag_Length;
            public int iTag_Found;
            public int iEndTag_Found;
            public bool bSkipTheRest;
            public FindSpecificTag(string sTag)
            {
                baTagToFind = null;
                iTag_Length = iTag_Found = -1;
                iEndTag_Found = -2;
                bSkipTheRest = false;
                SetTag(sTag);
            }
            public void SetTag(string sTag)
            {
                if (sTag.Length > MAX_TAGNAME_LENGTH)
                    sTag = sTag.Remove(MAX_TAGNAME_LENGTH);
                if (iTag_Length != sTag.Length)
                { // new length
                    iTag_Length = sTag.Length;
                    baTagToFind = new byte[iTag_Length];
                }
                for (int i = 0; i < sTag.Length; i++)
                    baTagToFind[i] = (byte)(sTag[i]);
            }
            public void ResetFound()
            {
                iTag_Found = -1;
                iEndTag_Found = -2;
                bSkipTheRest = false;
            }
            public bool FoundStartTag(byte b, ref bool bHasNoEndTag)
            {
                bool bRes = false;
                if (iTag_Found == -1)
                { // Find <
                    if (b == '<')
                        iTag_Found++;
                }
                else if (iTag_Found < iTag_Length)
                { // Find <tag
                    if (b == baTagToFind[iTag_Found])
                        iTag_Found++; // Start of tag found
                    else
                        iTag_Found = -1; // Mismatch
                }
                else // iTag_Found >= iTag_Length
                { // Find <tag> or <tag x="y">
                    if (b == '/')
                    { // <tag />
                        bSkipTheRest = true;
                        bHasNoEndTag = true;
                    }
                    else if (b == ' ')
                    {
                        bSkipTheRest = true;
                    }
                    else if (b == '>')
                    { // End found
                        iTag_Found = -1;
                        bRes = true;
                    }
                    else if (b == '<')
                    { // New start found
                        iTag_Found = 0;
                    }
                }
                return bRes;
            }
            public bool FoundEndTag(byte p)
            {
                bool bRes = false;
                if (iEndTag_Found == -2)
                { // Find <
                    if (p == '<')
                        iEndTag_Found++;
                }
                else if (iEndTag_Found == -1)
                { // Find </
                    if (p == '/')
                        iEndTag_Found++;
                    else
                        iEndTag_Found = -2;
                }
                else if (iEndTag_Found < iTag_Length)
                { // Find </tag
                    if (p == baTagToFind[iEndTag_Found])
                        iEndTag_Found++; // Start of tag found
                    else
                        iEndTag_Found = -2; // Mismatch
                }
                else // iEndTag_Found >= iTag_Length
                { // Find <tag> or <tag x="y">
                    iEndTag_Found = -2;
                    if (p == '>') // End found
                        bRes = true;
                }
                return bRes;
            }
        }
        protected class FindAnyTag
        {
            public byte[] baTagFound = new byte[MAX_TAGNAME_LENGTH];
            public int iTag_Length = -1;
            public bool bSkippingRest = false;
            public int iTagIndex = -1;
            public void ResetFound()
            {
                iTagIndex = -1;
                iTag_Length = -1;
                bSkippingRest = false;
            }

            public bool FindStartTag(byte b, ref bool bHasNoEndTag)
            {
                bool bRes = false;
                if (iTag_Length == -1)
                { // Find <
                    if (b == '<')
                        iTag_Length++;
                }
                else if (b == '/') // End found
                {
                    bHasNoEndTag = true;
                    bSkippingRest = true;
                }
                else if (b == '>') // End found
                    bRes = true;
                else if (b == '<') // New start found
                    iTag_Length = 0;
                else if (b == ' ' || iTag_Length >= MAX_TAGNAME_LENGTH)
                    bSkippingRest = true;
                else if (!bSkippingRest) // Only add length until we found a space
                    baTagFound[iTag_Length++] = b;
                return bRes;
            }
            public override string ToString()
            {
                if (iTag_Length == -1)
                    return "<empty>";
                StringBuilder sb = new StringBuilder(iTag_Length);
                for (int i = 0; i < iTag_Length; i++)
                    sb.Append((char)baTagFound[i]);
                return sb.ToString();
            }
        }
        protected XRowFindState findState;
        protected FindSpecificTag findRow = new FindSpecificTag();
        protected FindSpecificTag[] findCol;
        protected FindAnyTag currentTag;
        //
        #region Init
        public XmlRow(string sRowTag, string sColumnTags, Int64 pk, string fileName, int iMaxColumnCount)
            :base(pk, fileName, iMaxColumnCount)
        {
            findState = XRowFindState.XmlRowFindRowStartTag;
            findRow = new FindSpecificTag(sRowTag);
            findCol = new FindSpecificTag[MaxColumnCount];
            foreach (string sColumnTag in sColumnTags.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries))
            {
                string sColumnTagTrimmed = sColumnTag.Trim();
                if (sColumnTagTrimmed.Length > 0)
                {
                    findCol[iColumnCount++] = new FindSpecificTag(sColumnTag);
                    if (iColumnCount > iMaxColumnCount)
                        throw new Exception("Column count exceeds " + iMaxColumnCount.ToString());
                }
            }
            // current tag
            currentTag = new FindAnyTag();
        }
        public override void Reset(Int64 pk, string fileName)
        {
            base.Reset(pk, fileName);
            findState = XRowFindState.XmlRowFindRowStartTag;
            // Find column (unnecessary?)
            for (int i = 0; i < iColumnCount; i++)
                findCol[i].ResetFound();
        }
        #endregion Init
        #region Find data rows and data for the columns
        public override XRowFindState FindNext(ref byte[] ba, ref int iBuffer, int lenBuffer)
        { // Return true if new row filled, return false if
            if (findState == XRowFindState.XmlRowFoundRow)
                SetFindState(XRowFindState.XmlRowFindRowStartTag);
            while (findState != XRowFindState.XmlRowFoundRow && iBuffer < lenBuffer)
            {
                switch (findState)
                {
                    case XRowFindState.XmlRowFindRowStartTag:
                        FindRowStartTag(ref ba, ref iBuffer, lenBuffer, ref findState);
                        break;
                    case XRowFindState.XmlRowFindColTag:
                        FindColTag(ref ba, ref iBuffer, lenBuffer, ref currentTag, ref findState);
                        //Debug.WriteLine(currentTag.ToString());
                        break;
                    case XRowFindState.XmlRowSkipColTag:
                        SkipColTag(ref ba, ref iBuffer, lenBuffer, ref currentTag, ref findState);
                        break;
                    case XRowFindState.XmlRowSaveColTag:
                        SaveColTag(ref ba, ref iBuffer, lenBuffer, ref currentTag, ref findState); // SetFindState(FindState.SaveColTag); // We care about tag
                        //Debug.WriteLine(resultRow.sb[currentTag.iTagIndex]);
                        break;
                    case XRowFindState.XmlRowSkipRestOfEndTag:
                        SkipRestOfEndTag(ref ba, ref iBuffer, lenBuffer, ref findState); // SetFindState(FindState.SkipRestOfEndTag); // We care about tag
                        break;
                    case XRowFindState.XmlRowFoundRow:
                        break;
                    default:
                        throw new NotImplementedException("FindState unknown");
                    //break;
                }
            }
            return findState;
        }
        protected void SetFindState(XRowFindState newFindState)
        {
            switch (newFindState)
            {
                case XRowFindState.XmlRowFindRowStartTag:
                    findRow.ResetFound();
                    FindRowStartTag_bHasNoEndTag = false;
                    break;
                case XRowFindState.XmlRowFindColTag:
                    currentTag.ResetFound();
                    FindColTag_bFoundTag = false;
                    FindColTag_bFoundRowEndTag = false;
                    FindColTag_bHasNoEndTagOrIsEndTag = false;
                    break;
                case XRowFindState.XmlRowSkipColTag:
                    SkipColTag_cPrev = ' ';
                    break;
                case XRowFindState.XmlRowSaveColTag:
                    resultRow.sb[currentTag.iTagIndex].Length = 0; // Clear the destination-column before saving it
                    SaveColTag_cPrev = ' ';
                    break;
                case XRowFindState.XmlRowSkipRestOfEndTag:
                    break;
                case XRowFindState.XmlRowFoundRow:
                    break;
            }
            findState = newFindState;
        }
        bool FindRowStartTag_bHasNoEndTag = false;
        protected void FindRowStartTag(ref byte[] ba, ref int iBuffer, int lenBuffer, ref XRowFindState findState)
        { // public enum FindState { FindRowStartTag, FindColTag, SkipColTag, SaveColTag, FoundRow };
            while (iBuffer < lenBuffer && findState == XRowFindState.XmlRowFindRowStartTag)
            {
                if (findRow.FoundStartTag(ba[iBuffer++], ref FindRowStartTag_bHasNoEndTag)) // <row x>
                    if (FindRowStartTag_bHasNoEndTag)
                        findRow.ResetFound();
                    else
                        SetFindState(XRowFindState.XmlRowFindColTag); // We start on row;
            }
        }
        protected bool GetColumnIndexForTag(ref FindAnyTag currentTag)
        {
            currentTag.iTagIndex = -1; // -1 means not applicable
            for (int iCol = 0; currentTag.iTagIndex == -1 && iCol < iColumnCount; iCol++)
                if (findCol[iCol].baTagToFind.Length == currentTag.iTag_Length)
                {
                    bool bMatch = true;
                    for (int iB = 0; bMatch && iB < currentTag.iTag_Length; iB++)
                        if (findCol[iCol].baTagToFind[iB] != currentTag.baTagFound[iB])
                            bMatch = false;
                    if (bMatch)
                        currentTag.iTagIndex = iCol;
                }
            return currentTag.iTagIndex >= 0;
        }
        bool FindColTag_bFoundTag = false;
        bool FindColTag_bFoundRowEndTag = false;
        bool FindColTag_bHasNoEndTagOrIsEndTag = false;
        protected void FindColTag(ref byte[] ba, ref int iBuffer, int lenBuffer, ref FindAnyTag currentTag, ref XRowFindState findState)
        { // public enum FindState { FindRowStartTag, FindColTag, SkipColTag, SaveColTag, FoundRow };
            // <row x><col x>
            while (!FindColTag_bFoundTag && !FindColTag_bFoundRowEndTag && iBuffer < lenBuffer)
            {
                FindColTag_bFoundRowEndTag = findRow.FoundEndTag(ba[iBuffer]);
                FindColTag_bFoundTag = currentTag.FindStartTag(ba[iBuffer], ref FindColTag_bHasNoEndTagOrIsEndTag);
                iBuffer++;
            }
            if (FindColTag_bFoundRowEndTag)
                SetFindState(XRowFindState.XmlRowFoundRow); // End-tag found!
            else if (FindColTag_bFoundTag) // Get column-index of the found tag
                if (FindColTag_bHasNoEndTagOrIsEndTag)
                    SetFindState(XRowFindState.XmlRowFindColTag);
                else if (GetColumnIndexForTag(ref currentTag))
                    SetFindState(XRowFindState.XmlRowSaveColTag); // We care about tag
                else
                    SetFindState(XRowFindState.XmlRowSkipColTag); // We skip tag
        }
        char SkipColTag_cPrev = ' ';
        protected void SkipColTag(ref byte[] ba, ref int iBuffer, int lenBuffer, ref FindAnyTag currentTag, ref XRowFindState findState)
        { // public enum FindState { FindRowStartTag, FindColTag, SkipColTag, SaveColTag, FoundRow };
            // <row x><ignore_col x>skipped</ignore_col>
            while (findState == XRowFindState.XmlRowSkipColTag && iBuffer < lenBuffer)
            {
                char c = (char)ba[iBuffer++];
                if (SkipColTag_cPrev == '<' && c == '/')
                    SetFindState(XRowFindState.XmlRowSkipRestOfEndTag);
                SkipColTag_cPrev = c;
            }
        }
        char SaveColTag_cPrev = ' ';
        protected void SaveColTag(ref byte[] ba, ref int iBuffer, int lenBuffer, ref FindAnyTag currentTag, ref XRowFindState findState)
        { // public enum FindState { FindRowStartTag, FindColTag, SkipColTag, SaveColTag, FoundRow };
            // <row x><ignore_col x>saved</ignore_col>...save "saved"
            while (findState == XRowFindState.XmlRowSaveColTag && iBuffer < lenBuffer)
            {
                char c = (char)ba[iBuffer++];
                if (c != '<' || SaveColTag_cPrev == '<') // skip initial '<' in case of "</"...
                    if (SaveColTag_cPrev == '<' && c == '/')
                        SetFindState(XRowFindState.XmlRowSkipRestOfEndTag); // Done saving tag.
                    else
                    {
                        if (SaveColTag_cPrev == '<')
                            resultRow.sb[currentTag.iTagIndex].Append('<');
                        resultRow.sb[currentTag.iTagIndex].Append(c);
                    }
                SaveColTag_cPrev = c;
            }
        }
        protected void SkipRestOfEndTag(ref byte[] ba, ref int iBuffer, int lenBuffer, ref XRowFindState findState)
        { // public enum FindState { FindRowStartTag, FindColTag, SkipColTag, SaveColTag, FoundRow };
            // <row x><ignore_col x>saved</ignore_col>...save "saved"
            while (findState == XRowFindState.XmlRowSkipRestOfEndTag && iBuffer < lenBuffer)
                if (ba[iBuffer++] == (byte)'>')
                    SetFindState(XRowFindState.XmlRowFindColTag); // Ready for new tag.
        }
        #endregion Find data rows anddata for the columns
    }
    class XmlRowMemMapped: XmlRow
    {
        public XmlRowMemMapped(string sRowTag, string sColumnTags, Int64 pk, string fileName, int MaxColumnCount)
            : base(sRowTag, sColumnTags, pk, fileName, MaxColumnCount)
        {
        }
        public XRowFindState FindNext(MemoryMappedViewAccessor accessor, ref long lBuffer, long lLenBuffer)
        { // Return true if new row filled, return false if
            char cPrev;
            if (findState == XRowFindState.XmlRowFoundRow)
                SetFindState(XRowFindState.XmlRowFindRowStartTag);
            while (findState != XRowFindState.XmlRowFoundRow && lBuffer < lLenBuffer)
            {
                switch (findState)
                {
                    case XRowFindState.XmlRowFindRowStartTag:
                        bool bHasNoEndTag = false;
                        while (lBuffer < lLenBuffer && findState == XRowFindState.XmlRowFindRowStartTag)
                        {
                            if (findRow.FoundStartTag(accessor.ReadByte(lBuffer++), ref bHasNoEndTag)) // <row x>
                                if (bHasNoEndTag)
                                    findRow.ResetFound();
                                else
                                    SetFindState(XRowFindState.XmlRowFindColTag); // We start on row;
                        }
                        break;
                    case XRowFindState.XmlRowFindColTag: // <row x><col x>
                        bool bFoundTag = false;
                        bool bFoundRowEndTag = false;
                        bool bHasNoEndTagOrIsEndTag = false;
                        while (!bFoundTag && !bFoundRowEndTag && lBuffer < lLenBuffer)
                        {
                            bFoundRowEndTag = findRow.FoundEndTag(accessor.ReadByte(lBuffer));
                            bFoundTag = currentTag.FindStartTag(accessor.ReadByte(lBuffer), ref bHasNoEndTagOrIsEndTag);
                            lBuffer++;
                        }
                        if (bFoundRowEndTag)
                            SetFindState(XRowFindState.XmlRowFoundRow); // End-tag found!
                        else if (bFoundTag) // Get column-index of the found tag
                            if (bHasNoEndTagOrIsEndTag)
                                SetFindState(XRowFindState.XmlRowFindColTag);
                            else if (GetColumnIndexForTag(ref currentTag))
                                SetFindState(XRowFindState.XmlRowSaveColTag); // We care about tag
                            else
                                SetFindState(XRowFindState.XmlRowSkipColTag); // We skip tag
                        //Debug.WriteLine(currentTag.ToString());
                        break;
                    case XRowFindState.XmlRowSkipColTag:// <row x><ignore_col x>skipped</ignore_col>
                        cPrev = ' ';
                        while (findState == XRowFindState.XmlRowSkipColTag && lBuffer < lLenBuffer)
                        {
                            char c = (char)accessor.ReadByte(lBuffer++);
                            if (cPrev == '<' && c == '/')
                                SetFindState(XRowFindState.XmlRowSkipRestOfEndTag);
                            cPrev = c;
                        }
                        break;
                    case XRowFindState.XmlRowSaveColTag: // <row x><ignore_col x>saved</ignore_col>...save "saved"
                        resultRow.sb[currentTag.iTagIndex].Length = 0;
                        cPrev = ' ';
                        while (findState == XRowFindState.XmlRowSaveColTag && lBuffer < lLenBuffer)
                        {
                            char c = (char)accessor.ReadByte(lBuffer++);
                            if (c != '<' || cPrev == '<') // skip initial '<' in case of "</"...
                                if (cPrev == '<' && c == '/')
                                    SetFindState(XRowFindState.XmlRowSkipRestOfEndTag); // Done saving tag.
                                else
                                {
                                    if (cPrev == '<')
                                        resultRow.sb[currentTag.iTagIndex].Append('<');
                                    resultRow.sb[currentTag.iTagIndex].Append(c);
                                }
                            cPrev = c;
                        }
                        //Debug.WriteLine(resultRow.sb[currentTag.iTagIndex]);
                        break;
                    case XRowFindState.XmlRowSkipRestOfEndTag: // <row x><ignore_col x>saved</ignore_col>...save "saved"
                        while (findState == XRowFindState.XmlRowSkipRestOfEndTag && lBuffer < lLenBuffer)
                            if (accessor.ReadByte(lBuffer++) == (byte)'>')
                                SetFindState(XRowFindState.XmlRowFindColTag); // Ready for new tag.
                        break;
                    case XRowFindState.XmlRowFoundRow:
                        break;
                    default:
                        throw new NotImplementedException("FindState unknown");
                    //break;
                }
            }
            return findState;
        }
    }

    [Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName = "GetTags_Fill32")]
    public static IEnumerator GetXmlTags(string fileSpec, string rowtag, string columntags)
    {
        const long LEN_BUFFER_MAP = 0x10000L;     // 1KB-16MB - 0x400L..0x1000000L
        const int LEN_BUFFER_MEMORY = 0x4000;  // 1KB-1MB - 0x400L..0x100000L
        return GetXmlTags_Slice(fileSpec, rowtag, columntags, 1, 1, LEN_BUFFER_MEMORY, LEN_BUFFER_MAP);
    }
    [Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName = "GetTags_Fill32")]
    public static IEnumerator GetXmlTags_Slice(string fileSpec, string rowtag, string columntags, int iSlice, int iSliceCount, int iBufferSize, long lBufferMapSize)
    {
        XmlRow xmlRow = new XmlRow(rowtag, columntags, 0, fileSpec, 32); //XmlRow32MemMapped xmlRowMemMapped = new XmlRow32MemMapped(rowtag, columntags, 0, fileSpec);
        return GetTags_Slice(fileSpec, rowtag, columntags, iSlice, iSliceCount, iBufferSize, lBufferMapSize, xmlRow);
    }
    protected static IEnumerator GetTags_Slice(string fileSpec, string rowtag, string columntags, int iSlice, int iSliceCount
        , int iBufferSize, long lBufferMapSize, XRow xRow)
    {
        byte[] ba = new byte[iBufferSize]; // large (eg MB) buffer we allocate instantly not used before
        IEnumerator eFile = gbr.GetFilesFromFilespec(fileSpec);
        while (eFile.MoveNext())
        { // For each file...
            string fn = (string)eFile.Current;
            xRow.Reset(xRow.resultRow.PK, fn); //xRowMemMapped.Reset(xRow.resultRow.PK, fn);
            #region Read file slice
            FileReadPosition fileReadPosition = new FileReadPosition(iSlice, iSliceCount, fn, lBufferMapSize, iBufferSize);
            XRow.XRowFindState rowFindState = XRow.XRowFindState.XmlRowFindRowStartTag;
            MemoryMappedFileSecurity memoryMappedFileSecurity = new MemoryMappedFileSecurity();
            using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(
                new FileStream(fn, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 8, FileOptions.SequentialScan),
                null, 0, MemoryMappedFileAccess.Read, memoryMappedFileSecurity, HandleInheritability.None, false))
            { // For file...
                for (long lMapPosInFile = fileReadPosition.SliceStart; lMapPosInFile < fileReadPosition.FileSize && !fileReadPosition.SliceSkipRest; lMapPosInFile += fileReadPosition.BufferMapLength)
                { // For each map of file...
                    #region Read mapped buffer from file
                    long lMapBufferSize_Use = fileReadPosition.GetMapBufferSize(lMapPosInFile);
                    using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(lMapPosInFile, lMapBufferSize_Use, MemoryMappedFileAccess.Read))
                    { // For map...
                        long lMemoryPosInMap;
                        #region Read memory buffer from map 
                        //*// Copying a buffer from map...
                        for (lMemoryPosInMap = 0; lMemoryPosInMap < lMapBufferSize_Use && !fileReadPosition.SliceSkipRest; lMemoryPosInMap += fileReadPosition.BufferLength)
                        { // Read buffer
                            int iBufferLen = fileReadPosition.GetBufferSize(lMapBufferSize_Use, lMemoryPosInMap);
                            accessor.ReadArray<byte>(lMemoryPosInMap, ba, 0, iBufferLen);
                            #region Read row from memory buffer
                            int iBuffer = 0;
                            rowFindState = xRow.FindNext(ref ba, ref iBuffer, iBufferLen);
                            while (rowFindState == XRow.XRowFindState.XmlRowFoundRow)
                            {
                                xRow.resultRow.FilePosition = lMapPosInFile + lMemoryPosInMap + iBuffer;
                                yield return xRow.resultRow;
                                xRow.resultRow.Reset(xRow.resultRow.PK + 1);
                                rowFindState = xRow.FindNext(ref ba, ref iBuffer, iBufferLen);
                                if (lMapPosInFile + lMemoryPosInMap >= fileReadPosition.SliceEnded)
                                { // End of slice!
                                    fileReadPosition.SliceSkipRest = true;
                                    break;
                                }
                            }
                            #endregion Read row from memory buffer
                        }
                        //*/
                        #endregion Read memory buffer from map
                        #region Use map directly
                        // This is very slow when reading simple bytes
/*                      lMemoryPosInMap = 0;
                        rowFindState = xmlRowMemMapped.FindNext(accessor, ref lMemoryPosInMap, lMapBufferSize_Use);
                        while (rowFindState == XmlRow32.FindState.FoundRow)
                        {
                            yield return xmlRowMemMapped.resultRow;
                            xmlRowMemMapped.resultRow.Reset(xmlRowMemMapped.resultRow.PK + 1);
                            rowFindState = xmlRowMemMapped.FindNext(accessor, ref lMemoryPosInMap, lMapBufferSize_Use);
                        }
                        //*/
                        #endregion Use map directly
                    }
                    #endregion Read mapped buffer
                }
            }
            #endregion Read file slice
        }
    }
    public static void GetTags_Fill1(object row_raw, out Int64 oiPK, out string osFileName, out Int64 oiFilenameHash, out Int64 oiFilePosition, [SqlFacet(MaxSize = -1)] out string osCol00)
    {
        ResultRow row = (ResultRow)row_raw;
        oiPK = row.PK;
        osFileName = row.FileName;
        oiFilenameHash = row.FileNameHash;
        oiFilePosition = row.FilePosition;
        osCol00 = row.sb[00].ToString();
    }
    public static void GetTags_Fill2(object row_raw, out Int64 oiPK, out string osFileName, out Int64 oiFilenameHash, out Int64 oiFilePosition, [SqlFacet(MaxSize = -1)] out string osCol00, [SqlFacet(MaxSize = -1)] out string osCol01)
    {
        ResultRow row = (ResultRow)row_raw;
        oiPK = row.PK;
        osFileName = row.FileName;
        oiFilenameHash = row.FileNameHash;
        oiFilePosition = row.FilePosition;
        osCol00 = row.sb[00].ToString(); osCol01 = row.sb[01].ToString();
    }
    public static void GetTags_Fill4(object row_raw, out Int64 oiPK, out string osFileName, out Int64 oiFilenameHash, out Int64 oiFilePosition, [SqlFacet(MaxSize = -1)] out string osCol00, [SqlFacet(MaxSize = -1)] out string osCol01, [SqlFacet(MaxSize = -1)] out string osCol02, [SqlFacet(MaxSize = -1)] out string osCol03)
    {
        ResultRow row = (ResultRow)row_raw;
        oiPK = row.PK;
        osFileName = row.FileName;
        oiFilenameHash = row.FileNameHash;
        oiFilePosition = row.FilePosition;
        osCol00 = row.sb[00].ToString(); osCol01 = row.sb[01].ToString(); osCol02 = row.sb[02].ToString(); osCol03 = row.sb[03].ToString();
    }
    public static void GetTags_Fill8(object row_raw, out Int64 oiPK, out string osFileName, out Int64 oiFilenameHash, out Int64 oiFilePosition, [SqlFacet(MaxSize = -1)] out string osCol00, [SqlFacet(MaxSize = -1)] out string osCol01, [SqlFacet(MaxSize = -1)] out string osCol02, [SqlFacet(MaxSize = -1)] out string osCol03, [SqlFacet(MaxSize = -1)] out string osCol04, [SqlFacet(MaxSize = -1)] out string osCol05, [SqlFacet(MaxSize = -1)] out string osCol06, [SqlFacet(MaxSize = -1)] out string osCol07)
    {
        ResultRow row = (ResultRow)row_raw;
        oiPK = row.PK;
        osFileName = row.FileName;
        oiFilenameHash = row.FileNameHash;
        oiFilePosition = row.FilePosition;
        osCol00 = row.sb[00].ToString(); osCol01 = row.sb[01].ToString(); osCol02 = row.sb[02].ToString(); osCol03 = row.sb[03].ToString(); osCol04 = row.sb[04].ToString(); osCol05 = row.sb[05].ToString(); osCol06 = row.sb[06].ToString(); osCol07 = row.sb[07].ToString();
    }
    public static void GetTags_Fill16(object row_raw, out Int64 oiPK, out string osFileName, out Int64 oiFilenameHash, out Int64 oiFilePosition, [SqlFacet(MaxSize = -1)] out string osCol00, [SqlFacet(MaxSize = -1)] out string osCol01, [SqlFacet(MaxSize = -1)] out string osCol02, [SqlFacet(MaxSize = -1)] out string osCol03, [SqlFacet(MaxSize = -1)] out string osCol04, [SqlFacet(MaxSize = -1)] out string osCol05, [SqlFacet(MaxSize = -1)] out string osCol06, [SqlFacet(MaxSize = -1)] out string osCol07, [SqlFacet(MaxSize = -1)] out string osCol08, [SqlFacet(MaxSize = -1)] out string osCol09, [SqlFacet(MaxSize = -1)] out string osCol10, [SqlFacet(MaxSize = -1)] out string osCol11, [SqlFacet(MaxSize = -1)] out string osCol12, [SqlFacet(MaxSize = -1)] out string osCol13, [SqlFacet(MaxSize = -1)] out string osCol14, [SqlFacet(MaxSize = -1)] out string osCol15)
    {
        ResultRow row = (ResultRow)row_raw;
        oiPK = row.PK;
        osFileName = row.FileName;
        oiFilenameHash = row.FileNameHash;
        oiFilePosition = row.FilePosition;
        osCol00 = row.sb[00].ToString(); osCol01 = row.sb[01].ToString(); osCol02 = row.sb[02].ToString(); osCol03 = row.sb[03].ToString(); osCol04 = row.sb[04].ToString(); osCol05 = row.sb[05].ToString(); osCol06 = row.sb[06].ToString(); osCol07 = row.sb[07].ToString(); osCol08 = row.sb[08].ToString(); osCol09 = row.sb[09].ToString();
        osCol10 = row.sb[10].ToString(); osCol11 = row.sb[11].ToString(); osCol12 = row.sb[12].ToString(); osCol13 = row.sb[13].ToString(); osCol14 = row.sb[14].ToString(); osCol15 = row.sb[15].ToString();
    }
    public static void GetTags_Fill32(object row_raw, out Int64 oiPK, out string osFileName, out Int64 oiFilenameHash, out Int64 oiFilePosition, [SqlFacet(MaxSize = -1)] out string osCol00, [SqlFacet(MaxSize = -1)] out string osCol01, [SqlFacet(MaxSize = -1)] out string osCol02, [SqlFacet(MaxSize = -1)] out string osCol03, [SqlFacet(MaxSize = -1)] out string osCol04, [SqlFacet(MaxSize = -1)] out string osCol05, [SqlFacet(MaxSize = -1)] out string osCol06, [SqlFacet(MaxSize = -1)] out string osCol07, [SqlFacet(MaxSize = -1)] out string osCol08, [SqlFacet(MaxSize = -1)] out string osCol09, [SqlFacet(MaxSize = -1)] out string osCol10, [SqlFacet(MaxSize = -1)] out string osCol11, [SqlFacet(MaxSize = -1)] out string osCol12, [SqlFacet(MaxSize = -1)] out string osCol13, [SqlFacet(MaxSize = -1)] out string osCol14, [SqlFacet(MaxSize = -1)] out string osCol15, [SqlFacet(MaxSize = -1)] out string osCol16, [SqlFacet(MaxSize = -1)] out string osCol17, [SqlFacet(MaxSize = -1)] out string osCol18, [SqlFacet(MaxSize = -1)] out string osCol19, [SqlFacet(MaxSize = -1)] out string osCol20, [SqlFacet(MaxSize = -1)] out string osCol21, [SqlFacet(MaxSize = -1)] out string osCol22, [SqlFacet(MaxSize = -1)] out string osCol23, [SqlFacet(MaxSize = -1)] out string osCol24, [SqlFacet(MaxSize = -1)] out string osCol25, [SqlFacet(MaxSize = -1)] out string osCol26, [SqlFacet(MaxSize = -1)] out string osCol27, [SqlFacet(MaxSize = -1)] out string osCol28, [SqlFacet(MaxSize = -1)] out string osCol29, [SqlFacet(MaxSize = -1)] out string osCol30, [SqlFacet(MaxSize = -1)] out string osCol31)
    {
        ResultRow row = (ResultRow)row_raw;
        oiPK = row.PK;
        osFileName = row.FileName;
        oiFilenameHash = row.FileNameHash;
        oiFilePosition = row.FilePosition;
        osCol00 = row.sb[00].ToString(); osCol01 = row.sb[01].ToString(); osCol02 = row.sb[02].ToString(); osCol03 = row.sb[03].ToString(); osCol04 = row.sb[04].ToString(); osCol05 = row.sb[05].ToString(); osCol06 = row.sb[06].ToString(); osCol07 = row.sb[07].ToString(); osCol08 = row.sb[08].ToString(); osCol09 = row.sb[09].ToString();
        osCol10 = row.sb[10].ToString(); osCol11 = row.sb[11].ToString(); osCol12 = row.sb[12].ToString(); osCol13 = row.sb[13].ToString(); osCol14 = row.sb[14].ToString(); osCol15 = row.sb[15].ToString(); osCol16 = row.sb[16].ToString(); osCol17 = row.sb[17].ToString(); osCol18 = row.sb[18].ToString(); osCol19 = row.sb[19].ToString();
        osCol20 = row.sb[20].ToString(); osCol21 = row.sb[21].ToString(); osCol22 = row.sb[22].ToString(); osCol23 = row.sb[23].ToString(); osCol24 = row.sb[24].ToString(); osCol25 = row.sb[25].ToString(); osCol26 = row.sb[26].ToString(); osCol27 = row.sb[27].ToString(); osCol28 = row.sb[28].ToString(); osCol29 = row.sb[29].ToString();
        osCol30 = row.sb[30].ToString(); osCol31 = row.sb[31].ToString();
    }
    public static void GetTags_Fill64(object row_raw, out Int64 oiPK, out string osFileName, out Int64 oiFilenameHash, out Int64 oiFilePosition, [SqlFacet(MaxSize = -1)] out string osCol00, [SqlFacet(MaxSize = -1)] out string osCol01, [SqlFacet(MaxSize = -1)] out string osCol02, [SqlFacet(MaxSize = -1)] out string osCol03, [SqlFacet(MaxSize = -1)] out string osCol04, [SqlFacet(MaxSize = -1)] out string osCol05, [SqlFacet(MaxSize = -1)] out string osCol06, [SqlFacet(MaxSize = -1)] out string osCol07, [SqlFacet(MaxSize = -1)] out string osCol08, [SqlFacet(MaxSize = -1)] out string osCol09, [SqlFacet(MaxSize = -1)] out string osCol10, [SqlFacet(MaxSize = -1)] out string osCol11, [SqlFacet(MaxSize = -1)] out string osCol12, [SqlFacet(MaxSize = -1)] out string osCol13, [SqlFacet(MaxSize = -1)] out string osCol14, [SqlFacet(MaxSize = -1)] out string osCol15, [SqlFacet(MaxSize = -1)] out string osCol16, [SqlFacet(MaxSize = -1)] out string osCol17, [SqlFacet(MaxSize = -1)] out string osCol18, [SqlFacet(MaxSize = -1)] out string osCol19, [SqlFacet(MaxSize = -1)] out string osCol20, [SqlFacet(MaxSize = -1)] out string osCol21, [SqlFacet(MaxSize = -1)] out string osCol22, [SqlFacet(MaxSize = -1)] out string osCol23, [SqlFacet(MaxSize = -1)] out string osCol24, [SqlFacet(MaxSize = -1)] out string osCol25, [SqlFacet(MaxSize = -1)] out string osCol26, [SqlFacet(MaxSize = -1)] out string osCol27, [SqlFacet(MaxSize = -1)] out string osCol28, [SqlFacet(MaxSize = -1)] out string osCol29, [SqlFacet(MaxSize = -1)] out string osCol30, [SqlFacet(MaxSize = -1)] out string osCol31, [SqlFacet(MaxSize = -1)] out string osCol32, [SqlFacet(MaxSize = -1)] out string osCol33, [SqlFacet(MaxSize = -1)] out string osCol34, [SqlFacet(MaxSize = -1)] out string osCol35, [SqlFacet(MaxSize = -1)] out string osCol36, [SqlFacet(MaxSize = -1)] out string osCol37, [SqlFacet(MaxSize = -1)] out string osCol38, [SqlFacet(MaxSize = -1)] out string osCol39, [SqlFacet(MaxSize = -1)] out string osCol40, [SqlFacet(MaxSize = -1)] out string osCol41, [SqlFacet(MaxSize = -1)] out string osCol42, [SqlFacet(MaxSize = -1)] out string osCol43, [SqlFacet(MaxSize = -1)] out string osCol44, [SqlFacet(MaxSize = -1)] out string osCol45, [SqlFacet(MaxSize = -1)] out string osCol46, [SqlFacet(MaxSize = -1)] out string osCol47, [SqlFacet(MaxSize = -1)] out string osCol48, [SqlFacet(MaxSize = -1)] out string osCol49, [SqlFacet(MaxSize = -1)] out string osCol50, [SqlFacet(MaxSize = -1)] out string osCol51, [SqlFacet(MaxSize = -1)] out string osCol52, [SqlFacet(MaxSize = -1)] out string osCol53, [SqlFacet(MaxSize = -1)] out string osCol54, [SqlFacet(MaxSize = -1)] out string osCol55, [SqlFacet(MaxSize = -1)] out string osCol56, [SqlFacet(MaxSize = -1)] out string osCol57, [SqlFacet(MaxSize = -1)] out string osCol58, [SqlFacet(MaxSize = -1)] out string osCol59, [SqlFacet(MaxSize = -1)] out string osCol60, [SqlFacet(MaxSize = -1)] out string osCol61, [SqlFacet(MaxSize = -1)] out string osCol62, [SqlFacet(MaxSize = -1)] out string osCol63)
    {
        ResultRow row = (ResultRow)row_raw;
        oiPK = row.PK;
        osFileName = row.FileName;
        oiFilenameHash = row.FileNameHash;
        oiFilePosition = row.FilePosition;
        osCol00 = row.sb[00].ToString(); osCol01 = row.sb[01].ToString(); osCol02 = row.sb[02].ToString(); osCol03 = row.sb[03].ToString(); osCol04 = row.sb[04].ToString(); osCol05 = row.sb[05].ToString(); osCol06 = row.sb[06].ToString(); osCol07 = row.sb[07].ToString(); osCol08 = row.sb[08].ToString(); osCol09 = row.sb[09].ToString();
        osCol10 = row.sb[10].ToString(); osCol11 = row.sb[11].ToString(); osCol12 = row.sb[12].ToString(); osCol13 = row.sb[13].ToString(); osCol14 = row.sb[14].ToString(); osCol15 = row.sb[15].ToString(); osCol16 = row.sb[16].ToString(); osCol17 = row.sb[17].ToString(); osCol18 = row.sb[18].ToString(); osCol19 = row.sb[19].ToString();
        osCol20 = row.sb[20].ToString(); osCol21 = row.sb[21].ToString(); osCol22 = row.sb[22].ToString(); osCol23 = row.sb[23].ToString(); osCol24 = row.sb[24].ToString(); osCol25 = row.sb[25].ToString(); osCol26 = row.sb[26].ToString(); osCol27 = row.sb[27].ToString(); osCol28 = row.sb[28].ToString(); osCol29 = row.sb[29].ToString();
        osCol30 = row.sb[30].ToString(); osCol31 = row.sb[31].ToString(); osCol32 = row.sb[32].ToString(); osCol33 = row.sb[33].ToString(); osCol34 = row.sb[34].ToString(); osCol35 = row.sb[35].ToString(); osCol36 = row.sb[36].ToString(); osCol37 = row.sb[37].ToString(); osCol38 = row.sb[38].ToString(); osCol39 = row.sb[39].ToString();
        osCol40 = row.sb[40].ToString(); osCol41 = row.sb[41].ToString(); osCol42 = row.sb[42].ToString(); osCol43 = row.sb[43].ToString(); osCol44 = row.sb[44].ToString(); osCol45 = row.sb[45].ToString(); osCol46 = row.sb[46].ToString(); osCol47 = row.sb[47].ToString(); osCol48 = row.sb[48].ToString(); osCol49 = row.sb[49].ToString();
        osCol50 = row.sb[50].ToString(); osCol51 = row.sb[51].ToString(); osCol52 = row.sb[52].ToString(); osCol53 = row.sb[53].ToString(); osCol54 = row.sb[54].ToString(); osCol55 = row.sb[55].ToString(); osCol56 = row.sb[56].ToString(); osCol57 = row.sb[57].ToString(); osCol58 = row.sb[58].ToString(); osCol59 = row.sb[59].ToString();
        osCol60 = row.sb[60].ToString(); osCol61 = row.sb[61].ToString(); osCol62 = row.sb[62].ToString(); osCol63 = row.sb[63].ToString();
    }
};